<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<style>
    * {
        box-sizing: border-box;
    }

    .tip {
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        margin: auto;
        overflow: hidden;
        width: 280px;
        height: 120px;
        border-radius: 10px;
    }

    .tip .top {
        width: 100%;
        height: 36px;
        line-height: 36px;
        padding: 0 10px;
        background-color: slateblue;
        color: #fff;
    }

    .tip .top .close {
        position: absolute;
        right: 10px;
        cursor: pointer;
        transition: all .3s ease-in-out;
    }

    .tip .top .close:hover {
        color: tomato;
        transform: scale(1.3);
    }

    .tip .main {
        display: flex;
        justify-content: center;
        align-items: center;
        width: 100%;
        height: calc(100% - 66px);
    }

    .tip .footer {
        width: 100%;
        height: 30px;
        padding: 0 20px;
        background-color: slategrey;
        line-height: 30px;
        text-align: right;
    }
</style>

<body>

    <!-- <div class="tip"> -->
    <!-- <div class="top">这是标题<span class="close">x</span></div>
        <div class="main">这是内容</div>
        <div class="footer">
            <button>确认</button>
            <button>取消</button>
        </div> -->
    <!-- </div> -->

    <script>
        /*
            使用单例模式创建弹窗组件 无论调用多少次都只会存在一个tip
            如果不使用单例模式，每次new这个Tip类都会在dom中创建一个tip，不合理
        */
        // 单例模式方法   
        const Tip = (function () {
            // 业务逻辑实现类
            class Tip {
                constructor(options = { title: "弹窗", text: "", }) {
                    // 这里定义ele作为向页面中插入的弹窗元素
                    this.ele = document.createElement('div')
                    this.title = options.title
                    this.text = options.text
                    this.ele.className = 'tip'
                    this.cb = () => { }
                    // this.createElement();
                    this.bindEvent();
                    // 将创建的节点添加元素、绑定事件后 添加到body中
                    document.body.appendChild(this.ele)
                }

                // 创建元素
                createElement() {
                    this.ele.innerHTML = `
                    <div class="top">${this.title}
                        <span class="close">x</span>
                    </div>
                    <div class="main">${this.text}</div>
                    <div class="footer">
                        <button class="ok">确认</button>
                        <button class="cancel">取消</button>
                    </div>
                `
                }

                // 绑定事件
                bindEvent() {
                    // 这里采用事件委托的形式进行事件绑定，因为dom节点都是动态创建的，无法直接获取元素并在它们身上绑定事件
                    const that = this; // 可以不缓存this，而是使用箭头回调函数
                    this.ele.addEventListener('click', function (e) {
                        // console.log(this);
                        // console.log(this.ele);
                        e = e || window.event;
                        // 获取当前点击的元素
                        const target = e.target || e.srcElement;
                        if (target.className === 'close') {
                            that.cb();
                            that.ele.style.display = 'none';
                        }

                        if (target.className === 'cancel') {
                            that.ele.style.display = 'none';
                            that.cb(true);
                        }

                        if (target.className === 'ok') {
                            that.ele.style.display = 'none';
                            that.cb(false);
                        }
                    })
                }

            }
            let instance = null;
            return function (options, callback = () => { }) {
                // 如果实例不存在就创建实例
                if (!instance) instance = new Tip(options);
                // 为当前实例动态绑定callback
                instance.cb = callback
                // 每次调用弹窗方法时需要将none设置为block
                instance.ele.style.display = 'block'
                // 向tip中添加元素
                instance.createElement();
            }
        })()
        Tip({
            title: 'My Tip',
            text: '这是弹窗内容'
        }, (attr) => {
            console.log(attr);
            console.log('这是关闭回调');
        })
    </script>

</body>

</html>